package com.liu.yuoj.judge;

import cn.hutool.json.JSONUtil;
import com.liu.yuoj.common.ErrorCode;
import com.liu.yuoj.exception.BusinessException;
import com.liu.yuoj.exception.ThrowUtils;
import com.liu.yuoj.judge.codesandbox.CodeSandBox;
import com.liu.yuoj.judge.codesandbox.factory.CodeSandBoxFactory;
import com.liu.yuoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.liu.yuoj.judge.codesandbox.model.ExecuteCodeResponse;
import com.liu.yuoj.judge.codesandbox.proxy.CodeSandBoxProxy;
import com.liu.yuoj.judge.strategy.JudgeManager;
import com.liu.yuoj.judge.strategy.JudgeStrategy;
import com.liu.yuoj.model.dto.question.JudgeCase;
import com.liu.yuoj.model.dto.questionsubmit.JudgeInfo;
import com.liu.yuoj.model.entity.Question;
import com.liu.yuoj.model.entity.QuestionSubmit;
import com.liu.yuoj.model.enums.JudgeInfoMessageEnum;
import com.liu.yuoj.model.enums.QuestionSubmitLanguageEnum;
import com.liu.yuoj.model.enums.QuestionSubmitStatusEnum;
import com.liu.yuoj.service.QuestionService;
import com.liu.yuoj.service.QuestionSubmitService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author 刘渠好
 * @since 2025-04-04 23:08
 * 判题服务实现类
 */
@Service
public class JudgeServiceImpl implements JudgeService{

    @Resource
    @Lazy
    private QuestionSubmitService questionSubmitService;

    @Resource
    private QuestionService questionService;

    @Resource
    private JudgeManager judgeManager;

    @Value ("${codesandbox.type}")
    private String type;



    @Override
    public QuestionSubmit doJudge(long questionSubmitId) {
        //1.判断提交提交信息，题目信息
        if (questionSubmitId ==0){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"请求参数有误!");
        }
        //判断提交题目是否存在
        QuestionSubmit questionSubmit = questionSubmitService.getById (questionSubmitId);
        if (questionSubmit==null){
            throw new BusinessException (ErrorCode.NOT_FOUND_ERROR,"提交题目数据不存在!");
        }
        //判断题目是否存在
        Long questionId= questionSubmit.getQuestionId ();
        Question question = questionService.getById (questionId);
        if (question==null){
            throw new BusinessException (ErrorCode.NOT_FOUND_ERROR,"题目数据不存在!");
        }

        //2.判断提交题目状态
        if (!QuestionSubmitStatusEnum.WAITING.getValue ().equals (questionSubmit.getStatus ())){
            throw new BusinessException (ErrorCode.PARAMS_ERROR,"提交题目不在判题范围内!");
        }

        //3.更改题目状态为判题中
        QuestionSubmit questionSubmit1 = new QuestionSubmit ();
        questionSubmit1.setStatus (QuestionSubmitStatusEnum.RUNNING.getValue ());
        questionSubmit1.setId (questionSubmitId);
        questionSubmitService.updateById (questionSubmit1);

        //4.调用代码沙箱返回代码执行结果
        String judgeCase = question.getJudgeCase ();
        List<JudgeCase> list = JSONUtil.toList (judgeCase, JudgeCase.class);
        List<String> input = list.stream ().map (JudgeCase::getInput).collect (Collectors.toList ());
        String code = questionSubmit.getCode ();
        ExecuteCodeRequest codeRequest = ExecuteCodeRequest.builder ()
                .code (code)
                .language (QuestionSubmitLanguageEnum.JAVA)
                .input (input)
                .build ();
        //调用代码沙箱
        CodeSandBox sandBox = CodeSandBoxFactory.getCodeSandBox (type);
        CodeSandBoxProxy sandBoxProxy = new CodeSandBoxProxy (sandBox);
        ExecuteCodeResponse executeCodeResponse = sandBoxProxy.executeCode (codeRequest);
        List<String> output = executeCodeResponse.getOutput ();
        JudgeInfo judgeInfo = executeCodeResponse.getJudgeInfo ();
        //5.根据执行结果，设置提交题目的状态和信息
        JudgeContext judgeContext = new JudgeContext ();
        judgeContext.setQuestion (question);
        judgeContext.setOutputList (output);
        judgeContext.setJudgeInfo (judgeInfo);
        //判题执行
        JudgeStrategy strategy = judgeManager.getStrategy (questionSubmit);
        JudgeInfo judgeInfo1 = strategy.doJudge (judgeContext);

        //6.修改数据库中的判题结果
        QuestionSubmit questionSubmit2 = new QuestionSubmit ();
        questionSubmit2.setId (questionSubmitId);
        String judgeInfoStr = JSONUtil.toJsonStr (judgeInfo1);
        questionSubmit2.setJudgeInfo (judgeInfoStr);

        boolean b = questionSubmitService.updateById (questionSubmit2);
        ThrowUtils.throwIf (!b,ErrorCode.OPERATION_ERROR);

        //修改题目信息，通过了则题目通过数+1（执行的是异步操作，要放在异步中去判断）
        if (JudgeInfoMessageEnum.ACCEPT.getText ().equals (judgeInfo1.getMessage ())){
            Question question1 = new Question ();
            question1.setId (questionId);
            question1.setAcceptNum (Optional.ofNullable (question.getAcceptNum ()).orElse (0)+1);
            questionService.updateById (question1);
        }
       return questionSubmitService.getById (questionSubmitId);
    }
}
